package com.turing.data.engine;

import com.turing.common.util.StringUtils;
import com.turing.common.util.Tools;
import com.turing.data.vo.out.review.DependParamsVO;
import com.turing.data.vo.out.review.TaskElementVO;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import lombok.Getter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class M2BEngine {

    private static final Log logger = LogFactory.getLog(M2BEngine.class);


    @Getter
    private static String GROOVY_PATH;

    @Value("${groovy.script.path}")
    public void setGroovyPath(String groovyPath) {
        GROOVY_PATH = groovyPath;
    }

    public static void main(String[] args) {
        List<TaskElementVO.DrawResultVO> resultVOs = new ArrayList<>();
        TaskElementVO.DrawResultVO resultVO = new TaskElementVO.DrawResultVO();
        resultVO.setText("0.2_%");
        resultVOs.add(resultVO);
        TaskElementVO.DrawResultVO resultVOO = new TaskElementVO.DrawResultVO();
        resultVOO.setText("_15_%");
        resultVOs.add(resultVOO);
        DependParamsVO dependParams = null;

        //List< TaskElementVO.DrawResultVO > results = castModel2Business( "BasicManagementRate_9846_33",  resultVOs,dependParams );

        //System.out.println(results);
    }

    @SuppressWarnings("unchecked")
    public static List<TaskElementVO.DrawResultVO> filterNegativeElements(String packageName, String castName,  DependParamsVO dependParams) {


        File groovyFilePath = new File(GROOVY_PATH + "/" + packageName + "/filter/" + castName + "_filter.groovy");

        if (!groovyFilePath.exists()) {
            logger.error(String.format("Groovy Engine Error... Could not find Converter Script... Script ID %s, Path %s",
                    castName + "_filter", groovyFilePath.getAbsolutePath()));
            Map<String, List<TaskElementVO.DrawResultVO>> relatedModelElements = dependParams.getRelatedModelElements();
            if(Tools.isNotEmpty(relatedModelElements)){
                return relatedModelElements.entrySet().stream().findFirst().get().getValue();
            }
            return new ArrayList<>();
        }

        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
        try {
            Class groovyClass = groovyClassLoader.parseClass(groovyFilePath);

            GroovyObject o = (GroovyObject) groovyClass.newInstance();
            Object[] params = new Object[]{ dependParams };
            logger.info(String.format("calling groovy path %s", castName + "_filter"));
            return (List<TaskElementVO.DrawResultVO>) o.invokeMethod("doConvert", params);
        } catch (Exception e) {
            logger.error(e);
            return new ArrayList<>();
        }

    }

    @SuppressWarnings("unchecked")
    public static List<List<TaskElementVO.DrawResultVO>> filterTableElements(String packageName, String castName,  DependParamsVO dependParams) {


        File groovyFilePath = new File(GROOVY_PATH + "/" + packageName + "/filter/" + castName + "_filter.groovy");

        if (!groovyFilePath.exists()) {
            logger.error(String.format("Groovy Engine Error... Could not find Converter Script... Script ID %s, Path %s",
                    castName + "_filter", groovyFilePath.getAbsolutePath()));
            return new ArrayList<>();
        }

        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
        try {
            Class groovyClass = groovyClassLoader.parseClass(groovyFilePath);

            GroovyObject o = (GroovyObject) groovyClass.newInstance();
            Object[] params = new Object[]{ dependParams };
            logger.info(String.format("calling groovy path %s", castName + "_filter"));
            return (List<List<TaskElementVO.DrawResultVO>>) o.invokeMethod("doConvert", params);
        } catch (Exception e) {
            logger.error(e);
            return new ArrayList<>();
        }

    }

    /*
     * 将模型要素转换成业务要素
     * */
    @SuppressWarnings("unchecked")
    public static List<TaskElementVO.DrawResultVO> castModel2Business(String packageName, String castName, List<TaskElementVO.DrawResultVO> resultVOs, DependParamsVO dependParams) {

        if (resultVOs == null) {
            return null;
        }

        if (StringUtils.isEmpty(castName)) {
            return resultVOs;
        }

        File groovyFilePath = new File(GROOVY_PATH + "/" + packageName + "/transfer/" + castName + "_transfer.groovy");
        logger.info("groovy脚本路径:=======" + GROOVY_PATH);

        if (!groovyFilePath.exists()) {
            logger.error(String.format("Groovy Engine Error... Could not find Converter Script... Script ID %s, Path %s",
                    castName + "_transfer.groovy", groovyFilePath.getAbsolutePath()));
            for (TaskElementVO.DrawResultVO resultVO : resultVOs) {
                if (!StringUtils.isEmpty(resultVO.getText()) && StringUtils.isEmpty(resultVO.getBusinessValue())) {
                    resultVO.setBusinessValue(resultVO.getText());
                }
            }
            return resultVOs;
        }

        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
        try {
            Class groovyClass = groovyClassLoader.parseClass(groovyFilePath);

            GroovyObject o = (GroovyObject) groovyClass.newInstance();
            Object[] params = new Object[]{resultVOs, dependParams};
            logger.info(String.format("calling groovy path %s", castName + "transfer"));
            return (List<TaskElementVO.DrawResultVO>) o.invokeMethod("doConvert", params);
        } catch (Exception e) {
            logger.error(e);
            for (TaskElementVO.DrawResultVO resultVO : resultVOs) {
                if (!StringUtils.isEmpty(resultVO.getText()) && StringUtils.isEmpty(resultVO.getBusinessValue())) {
                    resultVO.setBusinessValue(resultVO.getText());
                }
            }
            return resultVOs;
        }


    }

    public M2BEngine() {
    }

    @SuppressWarnings("unchecked")
    public static List<String> mergeBusinessElements(String packageName, String castName, List<TaskElementVO.DrawResultVO> resultVOs, DependParamsVO dependParams) {

        if (resultVOs == null) {
            return null;
        }

        if (StringUtils.isEmpty(castName)) {
            return new ArrayList<>();
        }

        File groovyFilePath = new File(GROOVY_PATH + "/" + packageName + "/combine/" + castName + "_combine.groovy");

        List<String> defaultResult = new ArrayList<>();
        for (TaskElementVO.DrawResultVO resultVO : resultVOs) {
            if (!StringUtils.isEmpty(resultVO.getBusinessValue())) {
                defaultResult.add(resultVO.getBusinessValue());
            }
        }

        /*if(CollectionUtils.isEmpty(defaultResult)){
            for (TaskElementVO.DrawResultVO resultVO : resultVOs) {
                if(!StringUtils.isEmpty(resultVO.getText())){
                    defaultResult.add(resultVO.getText());
                }
            }
        }*/

        if (!groovyFilePath.exists()) {
            logger.error(String.format("Groovy Engine Error... Could not find MERGE Script... Script ID %s, Path %s",
                    castName + "_combine.groovy", groovyFilePath.getAbsolutePath()));
            return defaultResult;
        }

        GroovyClassLoader groovyClassLoader = new GroovyClassLoader(M2BEngine.class.getClassLoader());
        try {
            Class groovyClass = groovyClassLoader.parseClass(groovyFilePath);

            GroovyObject o = (GroovyObject) groovyClass.newInstance();

            Object[] params = new Object[]{resultVOs, dependParams};
            return (List<String>) o.invokeMethod("doConvert", params);
        } catch (Exception e) {
            e.printStackTrace();

            return defaultResult;
        }

    }

    public static boolean compare(String packageName, String castName, String busValue, String realValue) {

        if (StringUtils.isEmpty(castName)) {
            return false;
        }

        File groovyFilePath = new File(GROOVY_PATH + "/" + packageName + "/compare/" + castName + "_compare.groovy");

        if (!groovyFilePath.exists()) {
            logger.error(String.format("Groovy Engine Error... Could not find MERGE Script... Script ID %s, Path %s",
                    castName + "_compare.groovy", groovyFilePath.getAbsolutePath()));
            return busValue.equals(realValue);
        }

        GroovyClassLoader groovyClassLoader = new GroovyClassLoader(M2BEngine.class.getClassLoader());
        try {
            Class groovyClass = groovyClassLoader.parseClass(groovyFilePath);
            GroovyObject o = (GroovyObject) groovyClass.newInstance();
            Object[] params = new Object[]{busValue, realValue};
            return (Boolean) o.invokeMethod("doConvert", params);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }


    @SuppressWarnings("unchecked")
    public static List<TaskElementVO.DrawResultVO> doTemplateRuleConvertElements(String packageName, String eleName, List<TaskElementVO.DrawResultVO> resultVOs, DependParamsVO dependParams) {

        if (resultVOs == null) {
            return null;
        }

        if (StringUtils.isEmpty(eleName)) {
            return resultVOs;
        }

        File groovyFilePath = new File(GROOVY_PATH + "/" + packageName + "/rules/" + eleName + "_rule.groovy");

        if (!groovyFilePath.exists()) {
            logger.error(String.format("Groovy Engine Error... Could not find Converter Script... Script ID %s, Path %s",
                    eleName, groovyFilePath.getAbsolutePath()));
            return resultVOs;
        }

        GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
        try {
            Class groovyClass = groovyClassLoader.parseClass(groovyFilePath);

            GroovyObject o = (GroovyObject) groovyClass.newInstance();
            Object[] params = new Object[]{resultVOs, dependParams};
            logger.info(String.format("calling groovy path %s", eleName + "_rule"));
            List<TaskElementVO.DrawResultVO> doConvert = (List<TaskElementVO.DrawResultVO>) o.invokeMethod("doConvert", params);
            logger.info(String.format("finished calling groovy path %s", eleName + "_rule"));
            return doConvert;
        } catch (Exception e) {
            logger.error(e);
            return resultVOs;
        }

    }

}
